home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 2.6)
-
-
- try:
- import apt_pkg
- _have_apt_pkg = True
- except ImportError:
- _have_apt_pkg = False
-
- import new
- import re
- import string
- import sys
- import StringIO
- import UserDict
-
- class OrderedSet(object):
- """A set-like object that preserves order when iterating over it
-
- We use this to keep track of keys in Deb822Dict, because it's much faster
- to look up if a key is in a set than in a list.
- """
-
- def __init__(self, iterable = []):
- self._OrderedSet__set = set()
- self._OrderedSet__order = []
- for item in iterable:
- self.add(item)
-
-
-
- def add(self, item):
- if item not in self:
- self._OrderedSet__set.add(item)
- self._OrderedSet__order.append(item)
-
-
-
- def remove(self, item):
- self._OrderedSet__set.remove(item)
- self._OrderedSet__order.remove(item)
-
-
- def __iter__(self):
- return iter(self._OrderedSet__order)
-
-
- def __contains__(self, item):
- return item in self._OrderedSet__set
-
- append = add
-
- def extend(self, iterable):
- for item in iterable:
- self.add(item)
-
-
-
-
- class Deb822Dict(object, UserDict.DictMixin):
- '''A dictionary-like object suitable for storing RFC822-like data.
-
- Deb822Dict behaves like a normal dict, except:
- - key lookup is case-insensitive
- - key order is preserved
- - if initialized with a _parsed parameter, it will pull values from
- that dictionary-like object as needed (rather than making a copy).
- The _parsed dict is expected to be able to handle case-insensitive
- keys.
-
- If _parsed is not None, an optional _fields parameter specifies which keys
- in the _parsed dictionary are exposed.
- '''
-
- def __init__(self, _dict = None, _parsed = None, _fields = None):
- self._Deb822Dict__dict = { }
- self._Deb822Dict__keys = OrderedSet()
- self._Deb822Dict__parsed = None
- if _dict is not None:
- if hasattr(_dict, 'items'):
- items = _dict.items()
- else:
- items = list(_dict)
-
- try:
- for k, v in items:
- self[k] = v
- except ValueError:
- this = len(self._Deb822Dict__keys)
- len_ = len(items[this])
- raise ValueError('dictionary update sequence element #%d has length %d; 2 is required' % (this, len_))
- except:
- None<EXCEPTION MATCH>ValueError
-
-
- None<EXCEPTION MATCH>ValueError
-
-
- def __setitem__(self, key, value):
- key = _strI(key)
- self._Deb822Dict__keys.add(key)
- self._Deb822Dict__dict[key] = value
-
-
- def __getitem__(self, key):
- key = _strI(key)
-
- try:
- return self._Deb822Dict__dict[key]
- except KeyError:
- if self._Deb822Dict__parsed is not None and key in self._Deb822Dict__keys:
- return self._Deb822Dict__parsed[key]
- raise
- except:
- key in self._Deb822Dict__keys
-
-
-
- def __delitem__(self, key):
- key = _strI(key)
- del self._Deb822Dict__dict[key]
- self._Deb822Dict__keys.remove(key)
-
-
- def has_key(self, key):
- key = _strI(key)
- return key in self._Deb822Dict__keys
-
-
- def keys(self):
- return [ str(key) for key in self._Deb822Dict__keys ]
-
-
- def __repr__(self):
- return [] % []([ '%r: %r' % (k, v) for k, v in self.items() ])
-
-
- def __eq__(self, other):
- mykeys = self.keys()
- mykeys.sort()
- otherkeys = other.keys()
- otherkeys.sort()
- if not mykeys == otherkeys:
- return False
- for key in mykeys:
- if self[key] != other[key]:
- return False
-
- return True
-
-
- def copy(self):
- copy = self.__class__(self)
- return copy
-
-
-
- class Deb822(Deb822Dict):
-
- def __init__(self, sequence = None, fields = None, _parsed = None):
- '''Create a new Deb822 instance.
-
- :param sequence: a string, or any any object that returns a line of
- input each time, normally a file(). Alternately, sequence can
- be a dict that contains the initial key-value pairs.
-
- :param fields: if given, it is interpreted as a list of fields that
- should be parsed (the rest will be discarded).
-
- :param _parsed: internal parameter.
- '''
- if hasattr(sequence, 'items'):
- _dict = sequence
- sequence = None
- else:
- _dict = None
- Deb822Dict.__init__(self, _dict = _dict, _parsed = _parsed, _fields = fields)
- if sequence is not None:
-
- try:
- self._internal_parser(sequence, fields)
- except EOFError:
- pass
- except:
- None<EXCEPTION MATCH>EOFError
-
-
- None<EXCEPTION MATCH>EOFError
- self.gpg_info = None
-
-
- def iter_paragraphs(cls, sequence, fields = None, use_apt_pkg = True, shared_storage = False):
- """Generator that yields a Deb822 object for each paragraph in sequence.
-
- :param sequence: same as in __init__.
-
- :param fields: likewise.
-
- :param use_apt_pkg: if sequence is a file(), apt_pkg will be used
- if available to parse the file, since it's much much faster. Set
- this parameter to False to disable using apt_pkg.
- :param shared_storage: if sequence is a file(), use_apt_pkg is True,
- and shared_storage is True, yielded objects will share storage, so
- they can't be kept across iterations. (Also, PGP signatures won't
- be stripped.) By default, this parameter is False, causing a copy
- of the parsed data to be made through each iteration. Except for
- with raw Deb822 paragraphs (as opposed to _multivalued subclasses),
- the speed gained by setting shared_storage=True is marginal. This
- parameter has no effect if use_apt_pkg is False or apt_pkg is not
- available.
- """
- if _have_apt_pkg and use_apt_pkg and isinstance(sequence, file):
- parser = apt_pkg.ParseTagFile(sequence)
- while parser.Step() == 1:
- yield cls(fields = fields, _parsed = parsed)
- [] if shared_storage else []
- else:
- iterable = iter(sequence)
- x = cls(iterable, fields)
- while len(x) != 0:
- yield x
- x = cls(iterable, fields)
-
- iter_paragraphs = classmethod(iter_paragraphs)
-
- def _internal_parser(self, sequence, fields = None):
- single = re.compile('^(?P<key>\\S+)\\s*:\\s*(?P<data>\\S.*?)\\s*$')
- multi = re.compile('^(?P<key>\\S+)\\s*:\\s*$')
- multidata = re.compile('^\\s(?P<data>.+?)\\s*$')
-
- wanted_field = lambda f: if not fields is None:
- passf in fields
- if isinstance(sequence, basestring):
- sequence = sequence.splitlines()
-
- curkey = None
- content = ''
- for line in self.gpg_stripped_paragraph(sequence):
- m = single.match(line)
- if m:
- if curkey:
- self[curkey] += content
-
- if not wanted_field(m.group('key')):
- curkey = None
- continue
-
- curkey = m.group('key')
- self[curkey] = m.group('data')
- content = ''
- continue
-
- m = multi.match(line)
- if m:
- if curkey:
- self[curkey] += content
-
- if not wanted_field(m.group('key')):
- curkey = None
- continue
-
- curkey = m.group('key')
- self[curkey] = ''
- content = ''
- continue
-
- m = multidata.match(line)
- if m:
- content += '\n' + line
- continue
- continue
-
- if curkey:
- self[curkey] += content
-
-
-
- def __str__(self):
- return self.dump()
-
-
- def dump(self, fd = None):
- '''Dump the the contents in the original format
-
- If fd is None, return a string.
- '''
- if fd is None:
- fd = StringIO.StringIO()
- return_string = True
- else:
- return_string = False
- for key, value in self.iteritems():
- if not value or value[0] == '\n':
- fd.write('%s:%s\n' % (key, value))
- continue
- fd.write('%s: %s\n' % (key, value))
-
- if return_string:
- return fd.getvalue()
-
-
- def isSingleLine(self, s):
- if s.count('\n'):
- return False
- return True
-
-
- def isMultiLine(self, s):
- return not self.isSingleLine(s)
-
-
- def _mergeFields(self, s1, s2):
- if not s2:
- return s1
- if not s1:
- return s2
- if self.isSingleLine(s1) and self.isSingleLine(s2):
- delim = ' '
- L = (s1 + delim + s2).split(delim)
- L.sort()
- for item in L[1:]:
- merged = merged + delim + item
- prev = item
-
- return merged
- if self.isMultiLine(s1) and self.isMultiLine(s2):
- for item in s2.splitlines(True):
- if item not in s1.splitlines(True):
- s1 = s1 + '\n' + item
- continue
- self.isSingleLine(s2)
-
- return s1
- raise ValueError
-
-
- def mergeFields(self, key, d1, d2 = None):
- if d2 == None:
- x1 = self
- x2 = d1
- else:
- x1 = d1
- x2 = d2
- if key in x1 and key in x2:
- merged = self._mergeFields(x1[key], x2[key])
- elif key in x1:
- merged = x1[key]
- elif key in x2:
- merged = x2[key]
- else:
- raise KeyError
- if (key in x2) == None:
- self[key] = merged
- return None
- return merged
-
-
- def split_gpg_and_payload(sequence):
- '''Return a (gpg_pre, payload, gpg_post) tuple
-
- Each element of the returned tuple is a list of lines (with trailing
- whitespace stripped).
- '''
- gpg_pre_lines = []
- lines = []
- gpg_post_lines = []
- state = 'SAFE'
- gpgre = re.compile('^-----(?P<action>BEGIN|END) PGP (?P<what>[^-]+)-----$')
- blank_line = re.compile('^$')
- first_line = True
- for line in sequence:
- line = line.strip('\r\n')
- if first_line:
- if blank_line.match(line):
- continue
- else:
- first_line = False
-
- m = gpgre.match(line)
- if not m:
- if state == 'SAFE':
- if not blank_line.match(line):
- lines.append(line)
- elif not gpg_pre_lines:
- break
-
- elif state == 'SIGNED MESSAGE':
- if blank_line.match(line):
- state = 'SAFE'
- else:
- gpg_pre_lines.append(line)
- elif state == 'SIGNATURE':
- gpg_post_lines.append(line)
-
- state == 'SAFE'
- if m.group('action') == 'BEGIN':
- state = m.group('what')
- elif m.group('action') == 'END':
- gpg_post_lines.append(line)
- break
-
- if not blank_line.match(line):
- if not lines:
- gpg_pre_lines.append(line)
- else:
- gpg_post_lines.append(line)
- lines
-
- if len(lines):
- return (gpg_pre_lines, lines, gpg_post_lines)
- raise EOFError('only blank lines found in input')
-
- split_gpg_and_payload = staticmethod(split_gpg_and_payload)
-
- def gpg_stripped_paragraph(cls, sequence):
- return cls.split_gpg_and_payload(sequence)[1]
-
- gpg_stripped_paragraph = classmethod(gpg_stripped_paragraph)
-
- def get_gpg_info(self):
- '''Return a GpgInfo object with GPG signature information
-
- This method will raise ValueError if the signature is not available
- (e.g. the original text cannot be found)'''
- if not hasattr(self, 'raw_text'):
- raise ValueError, 'original text cannot be found'
- hasattr(self, 'raw_text')
- if self.gpg_info is None:
- self.gpg_info = GpgInfo.from_sequence(self.raw_text)
-
- return self.gpg_info
-
-
-
- class GpgInfo(dict):
- '''A wrapper around gnupg parsable output obtained via --status-fd
-
- This class is really a dictionary containing parsed output from gnupg plus
- some methods to make sense of the data.
- Keys are keywords and values are arguments suitably splitted.
- See /usr/share/doc/gnupg/DETAILS.gz'''
- uidkeys = ('GOODSIG', 'EXPSIG', 'EXPKEYSIG', 'REVKEYSIG', 'BADSIG')
-
- def valid(self):
- '''Is the signature valid?'''
- if not self.has_key('GOODSIG'):
- pass
- return self.has_key('VALIDSIG')
-
-
- def uid(self):
- '''Return the primary ID of the signee key, None is not available'''
- pass
-
-
- def from_output(out, err = None):
- '''Create a new GpgInfo object from gpg(v) --status-fd output (out) and
- optionally collect stderr as well (err).
-
- Both out and err can be lines in newline-terminated sequence or regular strings.'''
- n = GpgInfo()
- if isinstance(out, basestring):
- out = out.split('\n')
-
- if isinstance(err, basestring):
- err = err.split('\n')
-
- n.out = out
- n.err = err
- header = '[GNUPG:] '
- for l in out:
- if not l.startswith(header):
- continue
-
- l = l[len(header):]
- l = l.strip('\n')
- s = l.find(' ')
- key = l[:s]
- if key in GpgInfo.uidkeys:
- value = l[s + 1:].split(' ', 1)
- else:
- value = l[s + 1:].split(' ')
- n[key] = value
-
- return n
-
- from_output = staticmethod(from_output)
-
- def from_sequence(sequence, keyrings = [
- '/usr/share/keyrings/debian-keyring.gpg'], executable = [
- '/usr/bin/gpgv']):
- '''Create a new GpgInfo object from the given sequence.
-
- Sequence is a sequence of lines or a string
- executable is a list of args for subprocess.Popen, the first element being the gpg executable'''
- args = executable
- args.extend([
- '--status-fd',
- '1'])
- import os
- _[1]
- if '--keyring' not in args:
- raise IOError, 'cannot access none of given keyrings'
- '--keyring' not in args
- import subprocess
- p = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
- return GpgInfo.from_output(out, err)
-
- from_sequence = staticmethod(from_sequence)
-
- def from_file(target, *args):
- '''Create a new GpgInfo object from the given file, calls from_sequence(file(target), *args)'''
- return from_sequence(file(target), *args)
-
- from_file = staticmethod(from_file)
-
-
- class PkgRelation(object):
- '''Inter-package relationships
-
- Structured representation of the relationships of a package to another,
- i.e. of what can appear in a Deb882 field like Depends, Recommends,
- Suggests, ... (see Debian Policy 7.1).
- '''
- __dep_RE = re.compile('^\\s*(?P<name>[a-zA-Z0-9.+\\-]{2,})(\\s*\\(\\s*(?P<relop>[>=<]+)\\s*(?P<version>[0-9a-zA-Z:\\-+~.]+)\\s*\\))?(\\s*\\[(?P<archs>[\\s!\\w\\-]+)\\])?\\s*$')
- __comma_sep_RE = re.compile('\\s*,\\s*')
- __pipe_sep_RE = re.compile('\\s*\\|\\s*')
- __blank_sep_RE = re.compile('\\s*')
-
- def parse_relations(cls, raw):
- '''Parse a package relationship string (i.e. the value of a field like
- Depends, Recommends, Build-Depends ...)
- '''
-
- def parse_archs(raw):
- archs = []
- for arch in cls._PkgRelation__blank_sep_RE.split(raw.strip()):
- if len(arch) and arch[0] == '!':
- archs.append((False, arch[1:]))
- continue
- archs.append((True, arch))
-
- return archs
-
-
- def parse_rel(raw):
- match = cls._PkgRelation__dep_RE.match(raw)
- if match:
- parts = match.groupdict()
- d = {
- 'name': parts['name'] }
- if not parts['relop'] is None or parts['version'] is None:
- d['version'] = (parts['relop'], parts['version'])
- else:
- d['version'] = None
- if parts['archs'] is None:
- d['arch'] = None
- else:
- d['arch'] = parse_archs(parts['archs'])
- return d
- print >>sys.stderr, 'deb822.py: WARNING: cannot parse package relationship "%s", returning it raw' % raw
- return {
- 'name': raw,
- 'version': None,
- 'arch': None }
-
- tl_deps = cls._PkgRelation__comma_sep_RE.split(raw.strip())
- cnf = map(cls._PkgRelation__pipe_sep_RE.split, tl_deps)
- return (map,)((lambda or_deps: map(parse_rel, or_deps)), cnf)
-
- parse_relations = classmethod(parse_relations)
-
- def str(rels):
- '''Format to string structured inter-package relationships
-
- Perform the inverse operation of parse_relations, returning a string
- suitable to be written in a package stanza.
- '''
-
- def pp_arch(arch_spec):
- (excl, arch) = arch_spec
- if excl:
- return arch
- return '!' + arch
-
-
- def pp_atomic_dep(dep):
- s = dep['name']
- if dep.has_key('version') and dep['version'] is not None:
- s += ' (%s %s)' % dep['version']
-
- if dep.has_key('arch') and dep['arch'] is not None:
- s += ' [%s]' % string.join(map(pp_arch, dep['arch']))
-
- return s
-
-
- pp_or_dep = lambda deps: string.join(map(pp_atomic_dep, deps), ' | ')
- return string.join(map(pp_or_dep, rels), ', ')
-
- str = staticmethod(str)
-
-
- class _lowercase_dict(dict):
- '''Dictionary wrapper which lowercase keys upon lookup.'''
-
- def __getitem__(self, key):
- return dict.__getitem__(self, key.lower())
-
-
-
- class _PkgRelationMixin(object):
- """Package relationship mixin
-
- Inheriting from this mixin you can extend a Deb882 object with attributes
- letting you access inter-package relationship in a structured way, rather
- than as strings. For example, while you can usually use pkg['depends'] to
- obtain the Depends string of package pkg, mixing in with this class you
- gain pkg.depends to access Depends as a Pkgrel instance
-
- To use, subclass _PkgRelationMixin from a class with a _relationship_fields
- attribute. It should be a list of field names for which structured access
- is desired; for each of them a method wild be added to the inherited class.
- The method name will be the lowercase version of field name; '-' will be
- mangled as '_'. The method would return relationships in the same format of
- the PkgRelation' relations property.
-
- See Packages and Sources as examples.
- """
-
- def __init__(self, *args, **kwargs):
- self._PkgRelationMixin__relations = _lowercase_dict({ })
- self._PkgRelationMixin__parsed_relations = False
- for name in self._relationship_fields:
- keyname = name.lower()
- if self.has_key(name):
- self._PkgRelationMixin__relations[keyname] = None
- continue
- self._PkgRelationMixin__relations[keyname] = []
-
-
-
- def relations(self):
- '''Return a dictionary of inter-package relationships among the current
- and other packages.
-
- Dictionary keys depend on the package kind. Binary packages have keys
- like \'depends\', \'recommends\', ... while source packages have keys like
- \'build-depends\', \'build-depends-indep\' and so on. See the Debian policy
- for the comprehensive field list.
-
- Dictionary values are package relationships returned as lists of lists
- of dictionaries (see below for some examples).
-
- The encoding of package relationships is as follows:
- - the top-level lists corresponds to the comma-separated list of
- Deb822, their components form a conjuction, i.e. they have to be
- AND-ed together
- - the inner lists corresponds to the pipe-separated list of Deb822,
- their components form a disjunction, i.e. they have to be OR-ed
- together
- - member of the inner lists are dictionaries with the following keys:
- - name: package (or virtual package) name
- - version: A pair <operator, version> if the relationship is
- versioned, None otherwise. operator is one of "<<",
- "<=", "=", ">=", ">>"; version is the given version as
- a string.
- - arch: A list of pairs <polarity, architecture> if the
- relationship is architecture specific, None otherwise.
- Polarity is a boolean (false if the architecture is
- negated with "!", true otherwise), architecture the
- Debian archtiecture name as a string.
-
- Examples:
-
- "emacs | emacsen, make, debianutils (>= 1.7)" becomes
- [ [ {\'name\': \'emacs\'}, {\'name\': \'emacsen\'} ],
- [ {\'name\': \'make\'} ],
- [ {\'name\': \'debianutils\', \'version\': (\'>=\', \'1.7\')} ] ]
-
- "tcl8.4-dev, procps [!hurd-i386]" becomes
- [ [ {\'name\': \'tcl8.4-dev\'} ],
- [ {\'name\': \'procps\', \'arch\': (false, \'hurd-i386\')} ] ]
- '''
- if not self._PkgRelationMixin__parsed_relations:
- lazy_rels = (filter,)((lambda n: self._PkgRelationMixin__relations[n] is None), self._PkgRelationMixin__relations.keys())
- for n in lazy_rels:
- self._PkgRelationMixin__relations[n] = PkgRelation.parse_relations(self[n])
-
- self._PkgRelationMixin__parsed_relations = True
-
- return self._PkgRelationMixin__relations
-
- relations = property(relations)
-
-
- class _multivalued(Deb822):
- '''A class with (R/W) support for multivalued fields.
-
- To use, create a subclass with a _multivalued_fields attribute. It should
- be a dictionary with *lower-case* keys, with lists of human-readable
- identifiers of the fields as the values. Please see Dsc, Changes, and
- PdiffIndex as examples.
- '''
-
- def __init__(self, *args, **kwargs):
- Deb822.__init__(self, *args, **kwargs)
- for field, fields in self._multivalued_fields.items():
-
- try:
- contents = self[field]
- except KeyError:
- continue
-
- if self.isMultiLine(contents):
- self[field] = []
- updater_method = self[field].append
- else:
- self[field] = Deb822Dict()
- updater_method = self[field].update
- for line in filter(None, contents.splitlines()):
- updater_method(Deb822Dict(zip(fields, line.split())))
-
-
-
-
- def dump(self, fd = None):
- '''Dump the contents in the original format
-
- If fd is None, return a string.
- '''
- if fd is None:
- fd = StringIO.StringIO()
- return_string = True
- else:
- return_string = False
- for key in self.keys():
- keyl = key.lower()
- if keyl not in self._multivalued_fields:
- value = self[key]
- if not value or value[0] == '\n':
- fd.write('%s:%s\n' % (key, value))
- else:
- fd.write('%s: %s\n' % (key, value))
- value[0] == '\n'
- fd.write(key + ':')
- if hasattr(self[key], 'keys'):
- array = [
- self[key]]
- else:
- fd.write('\n')
- array = self[key]
- order = self._multivalued_fields[keyl]
-
- try:
- field_lengths = self._fixed_field_lengths
- except AttributeError:
- field_lengths = { }
-
- for item in array:
- for x in order:
- raw_value = str(item[x])
-
- try:
- length = field_lengths[keyl][x]
- except KeyError:
- value = raw_value
-
- value = (length - len(raw_value)) * ' ' + raw_value
- fd.write(' %s' % value)
-
- fd.write('\n')
-
-
- if return_string:
- return fd.getvalue()
-
-
-
- class _gpg_multivalued(_multivalued):
- """A _multivalued class that can support gpg signed objects
-
- This class's feature is that it stores the raw text before parsing so that
- gpg can verify the signature. Use it just like you would use the
- _multivalued class.
-
- This class only stores raw text if it is given a raw string, or if it
- detects a gpg signature when given a file or sequence of lines (see
- Deb822.split_gpg_and_payload for details).
- """
-
- def __init__(self, *args, **kwargs):
-
- try:
- sequence = args[0]
- except IndexError:
- sequence = kwargs.get('sequence', None)
-
- if sequence is not None:
- if isinstance(sequence, basestring):
- self.raw_text = sequence
- elif hasattr(sequence, 'items'):
- pass
- else:
-
- try:
- (gpg_pre_lines, lines, gpg_post_lines) = self.split_gpg_and_payload(sequence)
- except EOFError:
- gpg_pre_lines = lines = gpg_post_lines = []
-
- if gpg_pre_lines and gpg_post_lines:
- raw_text = StringIO.StringIO()
- raw_text.write('\n'.join(gpg_pre_lines))
- raw_text.write('\n\n')
- raw_text.write('\n'.join(lines))
- raw_text.write('\n\n')
- raw_text.write('\n'.join(gpg_post_lines))
- self.raw_text = raw_text.getvalue()
-
-
- try:
- args = list(args)
- args[0] = lines
- except IndexError:
- kwargs['sequence'] = lines
- except:
- None<EXCEPTION MATCH>IndexError
-
-
- None<EXCEPTION MATCH>IndexError
- _multivalued.__init__(self, *args, **kwargs)
-
-
-
- class Dsc(_gpg_multivalued):
- _multivalued_fields = {
- 'files': [
- 'md5sum',
- 'size',
- 'name'],
- 'checksums-sha1': [
- 'sha1',
- 'size',
- 'name'],
- 'checksums-sha256': [
- 'sha256',
- 'size',
- 'name'] }
-
-
- class Changes(_gpg_multivalued):
- _multivalued_fields = {
- 'files': [
- 'md5sum',
- 'size',
- 'section',
- 'priority',
- 'name'],
- 'checksums-sha1': [
- 'sha1',
- 'size',
- 'name'],
- 'checksums-sha256': [
- 'sha256',
- 'size',
- 'name'] }
-
- def get_pool_path(self):
- '''Return the path in the pool where the files would be installed'''
- s = self['files'][0]['section']
-
- try:
- (section, subsection) = s.split('/')
- except ValueError:
- section = 'main'
-
- if self['source'].startswith('lib'):
- subdir = self['source'][:4]
- else:
- subdir = self['source'][0]
- return 'pool/%s/%s/%s' % (section, subdir, self['source'])
-
-
-
- class PdiffIndex(_multivalued):
- _multivalued_fields = {
- 'sha1-current': [
- 'SHA1',
- 'size'],
- 'sha1-history': [
- 'SHA1',
- 'size',
- 'date'],
- 'sha1-patches': [
- 'SHA1',
- 'size',
- 'date'] }
-
- def _fixed_field_lengths(self):
- fixed_field_lengths = { }
- for key in self._multivalued_fields:
- if hasattr(self[key], 'keys'):
- continue
-
- length = self._get_size_field_length(key)
- fixed_field_lengths[key] = {
- 'size': length }
-
- return fixed_field_lengths
-
- _fixed_field_lengths = property(_fixed_field_lengths)
-
- def _get_size_field_length(self, key):
- lengths = [ len(str(item['size'])) for item in self[key] ]
- return max(lengths)
-
-
-
- class Release(_multivalued):
- '''Represents a Release file
-
- Set the size_field_behavior attribute to "dak" to make the size field
- length only as long as the longest actual value. The default,
- "apt-ftparchive" makes the field 16 characters long regardless.
- '''
- _multivalued_fields = {
- 'md5sum': [
- 'md5sum',
- 'size',
- 'name'],
- 'sha1': [
- 'sha1',
- 'size',
- 'name'],
- 'sha256': [
- 'sha256',
- 'size',
- 'name'] }
- __size_field_behavior = 'apt-ftparchive'
-
- def set_size_field_behavior(self, value):
- if value not in ('apt-ftparchive', 'dak'):
- raise ValueError("size_field_behavior must be either 'apt-ftparchive' or 'dak'")
- value not in ('apt-ftparchive', 'dak')
- self._Release__size_field_behavior = value
-
- size_field_behavior = property((lambda self: self._Release__size_field_behavior), set_size_field_behavior)
-
- def _fixed_field_lengths(self):
- fixed_field_lengths = { }
- for key in self._multivalued_fields:
- length = self._get_size_field_length(key)
- fixed_field_lengths[key] = {
- 'size': length }
-
- return fixed_field_lengths
-
- _fixed_field_lengths = property(_fixed_field_lengths)
-
- def _get_size_field_length(self, key):
- if self.size_field_behavior == 'apt-ftparchive':
- return 16
- if self.size_field_behavior == 'dak':
- lengths = [ len(str(item['size'])) for item in self[key] ]
- return max(lengths)
-
-
-
- class Sources(Dsc, _PkgRelationMixin):
- '''Represent an APT source package list'''
- _relationship_fields = [
- 'build-depends',
- 'build-depends-indep',
- 'build-conflicts',
- 'build-conflicts-indep']
-
- def __init__(self, *args, **kwargs):
- Dsc.__init__(self, *args, **kwargs)
- _PkgRelationMixin.__init__(self, *args, **kwargs)
-
-
-
- class Packages(Deb822, _PkgRelationMixin):
- '''Represent an APT binary package list'''
- _relationship_fields = [
- 'depends',
- 'pre-depends',
- 'recommends',
- 'suggests',
- 'breaks',
- 'conflicts',
- 'provides',
- 'replaces',
- 'enhances']
-
- def __init__(self, *args, **kwargs):
- Deb822.__init__(self, *args, **kwargs)
- _PkgRelationMixin.__init__(self, *args, **kwargs)
-
-
-
- class _CaseInsensitiveString(str):
- '''Case insensitive string.
- '''
-
- def __new__(cls, str_):
- s = str.__new__(cls, str_)
- s.str_lower = str_.lower()
- s.str_lower_hash = hash(s.str_lower)
- return s
-
-
- def __hash__(self):
- return self.str_lower_hash
-
-
- def __eq__(self, other):
- return self.str_lower == other.lower()
-
-
- def lower(self):
- return self.str_lower
-
-
- _strI = _CaseInsensitiveString
-